﻿using System.Linq;
using System.Web.Mvc;
using System.Web.Mvc.Ajax;
using System.Web.Routing;
using ExtendedMvc.Tests.Model;
using ExtendedMvc.Tests.Model.Entities;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace ExtendedMvc.Tests {


	/// <summary>
	///This is a test class for LinkTest and is intended
	///to contain all LinkTest Unit Tests
	///</summary>
	[TestClass()]
	public class AjaxLinkTest {

		private static DummyDataSource database;
		private static ModelViewPage<Dummy> view;

		private const string onClickScript = @"onclick=""Sys.Mvc.AsyncHyperlink.handleClick(this, new Sys.UI.DomEvent(event), { insertionMode: Sys.Mvc.InsertionMode.replace });""";
		private const string onClickScriptWithInsertAfter = @"onclick=""Sys.Mvc.AsyncHyperlink.handleClick(this, new Sys.UI.DomEvent(event), { insertionMode: Sys.Mvc.InsertionMode.insertAfter });""";
		private const string onClickScriptWithInsertBefore = @"onclick=""Sys.Mvc.AsyncHyperlink.handleClick(this, new Sys.UI.DomEvent(event), { insertionMode: Sys.Mvc.InsertionMode.insertBefore });""";
		private const string onClickScriptWithTargetId = @"onclick=""Sys.Mvc.AsyncHyperlink.handleClick(this, new Sys.UI.DomEvent(event), { insertionMode: Sys.Mvc.InsertionMode.replace, updateTargetId: &#39;targetId&#39; });""";
		private const string onClickScriptWithOnComplete = @"onclick=""Sys.Mvc.AsyncHyperlink.handleClick(this, new Sys.UI.DomEvent(event), { insertionMode: Sys.Mvc.InsertionMode.replace, onComplete: Function.createDelegate(this, function () { alert(&#39;me&#39;); }) });""";

		/// <summary>
		///Gets or sets the test context which provides
		///information about and functionality for the current test run.
		///</summary>
		public TestContext TestContext { get; set; }

		#region Additional test attributes
		// 
		//You can use the following additional attributes as you write your tests:
		//
		//Use ClassInitialize to run code before running the first test in the class
		[ClassInitialize()]
		public static void MyClassInitialize(TestContext testContext) {
			database = new DummyDataSource();
			var dummy = database.Dummies.All().First();
			view = MvcMockHelpers.FakeViewPage("Index", dummy);
			if (!RouteTable.Routes.Any()) {
				RouteTable.Routes.MapRoute(
					"Default", // Route name
					"{controller}/{action}/{id}", // URL with parameters
					new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
				);
			}
		}

		//Use ClassCleanup to run code after all tests in a class have run
		//[ClassCleanup()]
		//public static void MyClassCleanup() {
		//}
		//
		//Use TestInitialize to run code before running each test
		[TestInitialize()]
		public void MyTestInitialize() {
			view.ViewContext.ViewData.ModelState.Clear();
		}

		//Use TestCleanup to run code after each test has run
		//[TestCleanup()]
		//public void MyTestCleanup() {
		//}
		//
		#endregion

		/// <summary>
		///A test for Link Constructor
		///</summary>
		[TestMethod()]
		public void AjaxLink_WithUrlOnly() {
			// Arrange
			var linkContent = "Link Content";
			var linkUrl = "~/link/dummy.aspx";
			var outputUrl = "/link/dummy.aspx";
			var expectedOutput = string.Format(@"<a href=""{1}"" {2}>{0}</a>", linkContent, outputUrl, onClickScript);

			// Act
			var link = view.Ajax.Link(linkContent, linkUrl);
			var output = link.ToString();

			// Assert
			Assert.AreEqual<string>(expectedOutput, output);
		}

		/// <summary>
		///A test for Link Constructor
		///</summary>
		[TestMethod()]
		public void AjaxLink_WithAjaxOptions() {
			// Arrange
			var linkContent = "Link Content";
			var linkUrl = "~/link/dummy.aspx";
			var ajaxOptions = new AjaxOptions() {
				UpdateTargetId = "targetId"
			};
			var outputUrl = "/link/dummy.aspx";
			var expectedOutput = string.Format(@"<a href=""{1}"" {2}>{0}</a>", linkContent, outputUrl, onClickScriptWithTargetId);

			// Act
			var link = view.Ajax.Link(linkContent, linkUrl, ajaxOptions);
			var output = link.ToString();

			// Assert
			Assert.AreEqual<string>(expectedOutput, output);
		}

		/// <summary>
		///A test for Link Constructor
		///</summary>
		[TestMethod()]
		public void AjaxActionLink_WithDefaultActionOnly() {
			// Arrange
			var linkContent = "Link Content";
			var actionName = "Index";
			var outputUrl = "/";
			var expectedOutput = string.Format(@"<a href=""{1}"" {2}>{0}</a>", linkContent, outputUrl, onClickScript);

			// Act
			var link = view.Ajax.ActionLink(linkContent, actionName);
			var output = link.ToString();

			// Assert
			Assert.AreEqual<string>(expectedOutput, output);
		}

		/// <summary>
		///A test for Link Constructor
		///</summary>
		[TestMethod()]
		public void AjaxActionLink_WithOtherActionOnly() {
			// Arrange
			var linkContent = "Link Content";
			var actionName = "Edit";
			var outputUrl = "/Home/Edit";
			var expectedOutput = string.Format(@"<a href=""{1}"" {2}>{0}</a>", linkContent, outputUrl, onClickScript);

			// Act
			var link = view.Ajax.ActionLink(linkContent, actionName);
			var output = link.ToString();

			// Assert
			Assert.AreEqual<string>(expectedOutput, output);
		}

		/// <summary>
		///A test for Link Constructor
		///</summary>
		[TestMethod()]
		public void AjaxActionLink_WithDefaultActionAndDefaultController() {
			// Arrange
			var linkContent = "Link Content";
			var actionName = "Index";
			var controllerName = "Home";
			var outputUrl = "/";
			var expectedOutput = string.Format(@"<a href=""{1}"" {2}>{0}</a>", linkContent, outputUrl, onClickScript);

			// Act
			var link = view.Ajax.ActionLink(linkContent, actionName, controllerName);
			var output = link.ToString();

			// Assert
			Assert.AreEqual<string>(expectedOutput, output);
		}

		/// <summary>
		///A test for Link Constructor
		///</summary>
		[TestMethod()]
		public void AjaxActionLink_WithDefaultActionAndOtherController() {
			// Arrange
			var linkContent = "Link Content";
			var actionName = "Edit";
			var controllerName = "Home";
			var outputUrl = "/Home/Edit";
			var expectedOutput = string.Format(@"<a href=""{1}"" {2}>{0}</a>", linkContent, outputUrl, onClickScript);

			// Act
			var link = view.Ajax.ActionLink(linkContent, actionName, controllerName);
			var output = link.ToString();

			// Assert
			Assert.AreEqual<string>(expectedOutput, output);
		}

		/// <summary>
		///A test for Link Constructor
		///</summary>
		[TestMethod()]
		public void AjaxActionLink_WithOtherActionAndOtherController() {
			// Arrange
			var linkContent = "Link Content";
			var actionName = "Edit";
			var controllerName = "Other";
			var outputUrl = "/Other/Edit";
			var expectedOutput = string.Format(@"<a href=""{1}"" {2}>{0}</a>", linkContent, outputUrl, onClickScript);

			// Act
			var link = view.Ajax.ActionLink(linkContent, actionName, controllerName);
			var output = link.ToString();

			// Assert
			Assert.AreEqual<string>(expectedOutput, output);
		}

		/// <summary>
		///A test for Link Constructor
		///</summary>
		[TestMethod()]
		public void AjaxActionLink_WithAjaxOptions() {
			// Arrange
			var linkContent = "Link Content";
			var ajaxOptions = new AjaxOptions() {
				UpdateTargetId = "targetId"
			};
			var outputUrl = "/";
			var expectedOutput = string.Format(@"<a href=""{1}"" {2}>{0}</a>", linkContent, outputUrl, onClickScriptWithTargetId);

			// Act
			var link = view.Ajax.ActionLink(linkContent, ajaxOptions: ajaxOptions);
			var output = link.ToString();

			// Assert
			Assert.AreEqual<string>(expectedOutput, output);
		}

		/// <summary>
		///A test for Link Constructor
		///</summary>
		[TestMethod()]
		public void AjaxActionLink_WithRouteValues() {
			// Arrange
			var linkContent = "Link Content";
			var actionName = "Index";
			var routeValues = new { id = 5, name = "blah" };
			var outputUrl = "/Home/Index/5?name=blah";
			var expectedOutput = string.Format(@"<a href=""{1}"" {2}>{0}</a>", linkContent, outputUrl, onClickScript);

			// Act
			var link = view.Ajax.ActionLink(linkContent, actionName, routeValues: routeValues);
			var output = link.ToString();

			// Assert
			Assert.AreEqual<string>(expectedOutput, output);
		}

		/// <summary>
		///A test for Link Constructor
		///</summary>
		[TestMethod()]
		public void AjaxRouteLink_WithValidRouteNameOnly() {
			// Arrange
			var linkContent = "Link Content";
			var routeName = "Default";
			var outputUrl = "/";
			var expectedOutput = string.Format(@"<a href=""{1}"" {2}>{0}</a>", linkContent, outputUrl, onClickScript);

			// Act
			var link = view.Ajax.RouteLink(linkContent, routeName);
			var output = link.ToString();

			// Assert
			Assert.AreEqual<string>(expectedOutput, output);
		}

		/// <summary>
		///A test for Link Constructor
		///</summary>
		[TestMethod()]
		[ExpectedException(typeof(System.ArgumentException))]
		public void AjaxRouteLink_WithInvalidRouteNameOnly() {
			// Arrange
			var linkContent = "Link Content";
			var routeName = "Other";

			// Act
			var link = view.Ajax.RouteLink(linkContent, routeName);
		}

		/// <summary>
		///A test for Link Constructor
		///</summary>
		[TestMethod()]
		public void AjaxRouteLink_WithProtocol() {
			// Arrange
			var linkContent = "Link Content";
			var routeName = "Default";
			var protocol = "https";
			var outputUrl = "https://localhost/";
			var expectedOutput = string.Format(@"<a href=""{1}"" {2}>{0}</a>", linkContent, outputUrl, onClickScript);

			// Act
			var link = view.Ajax.RouteLink(linkContent, routeName, protocol);
			var output = link.ToString();

			// Assert
			Assert.AreEqual<string>(expectedOutput, output);
		}

		/// <summary>
		///A test for Link Constructor
		///</summary>
		[TestMethod()]
		public void AjaxRouteLink_WithHostName() {
			// Arrange
			var linkContent = "Link Content";
			var routeName = "Default";
			var hostName = "server";
			var outputUrl = "http://server/";
			var expectedOutput = string.Format(@"<a href=""{1}"" {2}>{0}</a>", linkContent, outputUrl, onClickScript);

			// Act
			var link = view.Ajax.RouteLink(linkContent, routeName, hostName: hostName);
			var output = link.ToString();

			// Assert
			Assert.AreEqual<string>(expectedOutput, output);
		}

		/// <summary>
		///A test for Link Constructor
		///</summary>
		[TestMethod()]
		public void AjaxRouteLink_WithFragment() {
			// Arrange
			var linkContent = "Link Content";
			var routeName = "Default";
			var fragment = "123";
			var outputUrl = "/#123";
			var expectedOutput = string.Format(@"<a href=""{1}"" {2}>{0}</a>", linkContent, outputUrl, onClickScript);

			// Act
			var link = view.Ajax.RouteLink(linkContent, routeName, fragment: fragment);
			var output = link.ToString();

			// Assert
			Assert.AreEqual<string>(expectedOutput, output);
		}

		/// <summary>
		///A test for Link Constructor
		///</summary>
		[TestMethod()]
		public void AjaxRouteLink_WithRouteValues() {
			// Arrange
			var linkContent = "Link Content";
			var routeName = "Default";
			var routeValues = new { id = 5, name = "blah" };
			var outputUrl = "/Home/Index/5?name=blah";
			var expectedOutput = string.Format(@"<a href=""{1}"" {2}>{0}</a>", linkContent, outputUrl, onClickScript);

			// Act
			var link = view.Ajax.RouteLink(linkContent, routeName, routeValues: routeValues);
			var output = link.ToString();

			// Assert
			Assert.AreEqual<string>(expectedOutput, output);
		}

		/// <summary>
		///A test for Link Constructor
		///</summary>
		[TestMethod()]
		public void AjaxRouteLink_WithAjaxOptions_TargetId() {
			// Arrange
			var linkContent = "Link Content";
			var ajaxOptions = new AjaxOptions() {
				UpdateTargetId = "targetId"
			};
			var outputUrl = "/";
			var expectedOutput = string.Format(@"<a href=""{1}"" {2}>{0}</a>", linkContent, outputUrl, onClickScriptWithTargetId);

			// Act
			var link = view.Ajax.RouteLink(linkContent, ajaxOptions: ajaxOptions);
			var output = link.ToString();

			// Assert
			Assert.AreEqual<string>(expectedOutput, output);
		}

		/// <summary>
		///A test for Link Constructor
		///</summary>
		[TestMethod()]
		public void AjaxRouteLink_WithAjaxOptions_OnComplete() {
			// Arrange
			var linkContent = "Link Content";
			var ajaxOptions = new AjaxOptions() {
				OnComplete = "function () { alert('me'); }"
			};
			var outputUrl = "/";
			var expectedOutput = string.Format(@"<a href=""{1}"" {2}>{0}</a>", linkContent, outputUrl, onClickScriptWithOnComplete);

			// Act
			var link = view.Ajax.RouteLink(linkContent, ajaxOptions: ajaxOptions);
			var output = link.ToString();

			// Assert
			Assert.AreEqual<string>(expectedOutput, output);
		}

		/// <summary>
		///A test for Link Constructor
		///</summary>
		[TestMethod()]
		public void AjaxRouteLink_WithAjaxOptions_InsertionMode_InsertAfter() {
			// Arrange
			var linkContent = "Link Content";
			var ajaxOptions = new AjaxOptions() {
				InsertionMode = InsertionMode.InsertAfter
			};
			var outputUrl = "/";
			var expectedOutput = string.Format(@"<a href=""{1}"" {2}>{0}</a>", linkContent, outputUrl, onClickScriptWithInsertAfter);

			// Act
			var link = view.Ajax.RouteLink(linkContent, ajaxOptions: ajaxOptions);
			var output = link.ToString();

			// Assert
			Assert.AreEqual<string>(expectedOutput, output);
		}

		/// <summary>
		///A test for Link Constructor
		///</summary>
		[TestMethod()]
		public void AjaxRouteLink_WithAjaxOptions_InsertionMode_InsertBefore() {
			// Arrange
			var linkContent = "Link Content";
			var ajaxOptions = new AjaxOptions() {
				InsertionMode = InsertionMode.InsertBefore
			};
			var outputUrl = "/";
			var expectedOutput = string.Format(@"<a href=""{1}"" {2}>{0}</a>", linkContent, outputUrl, onClickScriptWithInsertBefore);

			// Act
			var link = view.Ajax.RouteLink(linkContent, ajaxOptions: ajaxOptions);
			var output = link.ToString();

			// Assert
			Assert.AreEqual<string>(expectedOutput, output);
		}
	}
}
